home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-05
/
pdclk139.zip
/
IP.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-05-17
|
55KB
|
2,314 lines
; ip.asm
;========================================================================
; Copyright (C) 1991 by Jan.Engvald@ldc.lu.se, see file COPYING.
;************************************************************************
;************************************************************************
;*
;* UDP/IP library
;*
;* This library is in a transition phase from a PDCLKSET specific library
;* into a multiprocess, reentrant, any hardware type, general UDP/IP
;* library. The buffers used have a descriptor part and a packet part.
;* The descriptor part is used to allow reentrancy, different physical
;* address lengths and varying number of IP options.
;*
;* In this library DS:BX always points to the descriptor buffer, DS:DI
;* usually points to the physical header/IP header/UDP header part of
;* the IP packet buffer and DX,AX often contains an IP number in network
;* byte order (DL,DH,AL,AH). For efficiency reasons, IP numbers are
;* searched last half first (first halves are often equal).
;*
;* As this library is still evolving, you can not assume that it looks
;* the same in the next release. In particular, if you are using any of
;* of the subroutines, check if their calls or results have been changed.
;*
;* The current implementation is RFC791 (IP) and RFC1122 (host requirements)
;* compliant, except for a few cases: I havn't found a reasonable solution
;* on how to report back to the application ICMP errors like parameter
;* problem, protocol and port unreachables, and fragment reassembly time
;* exceeded. Also, IP options are allowed, but the interpretation and handling
;* must be done by the application. Apart from the above, it is a de luxe
;* implementation that includes things like multiple default gateways,
;* sending protocol and port unreachables, IP type of service handling (not
;* tested), fragment reassembly and source quench introduced delay.
;*
;************************************************************************
;************************************************************************
; send errors:
SERRUNREACH equ 0 ; host or net unreachable
SERRNOBUF equ 2 ; temporary out of buffers
SERRNOARP equ 4 ; got no ARP reply
SERRTIMOUT equ 6 ; general timeout
SERRNOTRAF equ 8 ; received no traffic from dst
ICMP_PROT equ 1 ; Internet Control Msg Prot
UDP_PROT equ 17 ; IP protocol type UDP
Descriptor struc
dLink LinkStruc <> ; next & prev links
; dIOCB iocb <> ; pkt drvr hi perf struc
dPtrPhys dw 0 ; ptr to physical hdr
dPtrIp dw 0 ; ptr to IP hdr
dPtrUdp dw 0 ; ptr to UDP hdr
dPktLen dw 0 ; packet length (bytes)
dPktEnd dw 0 ; end of packet
dTimOut2Msg equ dPktEnd ; Timeout msg for findsends
dSqDelay dw 0 ; source quench delay (ms)
dWaitEvent dw 0 ; event to wait for
dPtrFrag equ dWaitEvent ; ptr to defargment listhead
dTimOutMsg dw 0 ; to be displayed at timeout
dTickResend dw 1*18 ; resend start interval (ticks)
dTickTimeout dw 4*18 ; timeout ticks (in 1/18 s)
dTick2Timeout dw 14*18 ; second timeout
dIdxHwDst equ dSqDelay ; arp table index for hw dst
dIdxIpDst equ dTick2Timeout ; arp table index for IP dst
dAdjust equ (4-(($-dLink) and 3)) and 3
if dAdjust
db dAdjust dup (0)
endif
dGwys2Chk db 0 ; # of untried gateways
dSnap db 0 ; 802.3 snaps used
dPtrDes dw 0 ; ptr to start of descriptor
dHwDst equ $-dLink ; (part of pd packet)
DESCRLEN equ $-dLink
Descriptor ends
HwStruc struc
hEthDst db 6 dup (0) ; Ethernet destination address
hEthSrc db 6 dup (0) ; my Ether addr
hProtType dw 0008 ; 0800 = IP
HWHDRLEN equ $-hEthDst
HwStruc ends
SnapStruc struc
sDSAP db 170
sSSAP db 170
sContr db 3
sOrgCode db 0,0,0
sProt db 08, 00
SNAPLEN equ $-sDSAP
SnapStruc ends
IpStruc struc
iIpVerHlen db 45h ; ver 4, 5 32-bit hdr words
iIpTos db 0 ; type of service
iIpLen dw 0 ; IP packet length
iIpId dw 0100h ; id 0001
iIpFlFrag dw 0 ; no flags or fragments
iIpTtl db 90 ; time to live
iIpProt db 0 ; 17 = udp
iIpXsum dw 0 ; header checksum
iIpSrc dw 0, 0 ; Don't know my IP nmbr
iIpDst dw 0ffffh, 0ffffh ; local net broadcast IP
iIpOptions equ $-iIpVerHlen
IPHDRLEN equ $-iIpVerHlen
IpStruc ends
UdpStruc struc
uUdpSrc dw 4400h ; source port 44h = 68
uUdpDst dw 4300h ; dest port 43h = 67
uUdpLen dw 0 ; length in bytes
uUdpXsum dw 0 ; udp checksum
uUdpData equ $-uUdpSrc
UDPHDRLEN equ $-uUdpSrc
UdpStruc ends
BootpStruc struc
uUdpStruc UdpStruc <>
uBotOp db 1 ; bootp request
uBotHtype db 0 ; hardware type
uBotHlen db 0 ; hardware addr lenght
uBotHops db 0 ; hops
uBotXid dw 0, 0 ; transaction id
uBotSecs dw 0001 ; 0100h seconds since boot
uBotUnused dw 0 ; not defined
uBotCliIp dw 0, 0 ; Client IP unknown
uBotYourIp dw 0, 0 ; my IP yet unknown
uBotServIp dw 0, 0 ; Server IP
uBotGwyIp dw 0, 0 ; Gateway IP
uBotCliHwAd db 16 dup (0) ; My Hardware address
uBotSname db 64 dup (0) ; server name
uBotFilNam db 128 dup (0) ; file name
uBotMagNum dw 8263h, 6353h ; Magic number
uBotVend db 64-4 dup (0) ; Vendor specific area
BpDataLen = $-uBotOp
BootpStruc ends
IcmpStruc struc
uIcmpTypecode dw 0
uIcmpXsum dw 0
uIcmpData dw 0, 0
uIcmpIpHdr dw iIpOptions+4 dup (0)
ICMPHDRLEN equ uIcmpIpHdr-uIcmpTypecode
IcmpStruc ends
BootpFrame struc
fDescriptor Descriptor <>
fHwStruc HwStruc <>
fIpStruc IpStruc <>
fBotStruc BootpStruc <>
BpLen = $-fHwStruc
BootpFrame ends
even
Events dw 1 ; =1 so DONT_WAIT always true
DONT_WAIT equ 1
GOT_BOOTP equ 2
GOT_ARPREPLY equ 4
GOT_TIMEREPLY equ 8
GOT_ARPREQ equ 16
GOT_ICMPMSG equ 32
GOT_NSREPLY equ 64
GenFlags dw 0
ARGZONE equ 2
ARGZONESPEC equ 4
DSTNOW equ 8
IS_386 equ 16
TBL_READY equ 32
DBGINTERR equ 08000h
MySegm dw 0
Hlen dw 0
H2Len dw 0
MyMask dw 2 dup (0h)
MyNet dw 2 dup (0h)
IpHandle dw 0
IpIdCounter dw 0
InSendAndW dw 0
ifndef MAXDEFGWYS
MAXDEFGWYS equ 4
endif
DefGwyIndex dw 0
DefGwyNum dw 0
DefGwys dw MAXDEFGWYS*2 dup (0)
if TBLBUILD or PINGCLIENT
DefNSnum dw 0
DefNS dw MAXDEFNS*2 dup (0)
endif ; TBLBUILD or PINGCLIENT
ifndef ROUTESLOTS
ROUTESLOTS equ 8
endif
; The route table contains information on hosts behind gateways.
;
; If we don't receive anything from an IP number within one minute after we
; last sent to it, we return SERRNOTRAF on the next send. This is cleared
; after another minute.
RouteTabIpD2 dw ROUTESLOTS dup (0) ; destination IP #
RouteTabIpD1 dw ROUTESLOTS dup (0)
RouteTabTos dw ROUTESLOTS dup (0) ; type of service
RouteTabIpG2 dw ROUTESLOTS dup (0) ; gateway IP #
RouteTabIpG1 dw ROUTESLOTS dup (0)
RouteTabTrTx dw ROUTESLOTS dup (0) ; transmitt timer
RouteTabTrRx dw ROUTESLOTS dup (0) ; receive timer
RouteTabFlags dw ROUTESLOTS dup (0) ; flags (must follow TrRx)
RouteTabTrSq dw ROUTESLOTS dup (0) ; source quench timer
RouteTabSqDelay dw ROUTESLOTS dup (0) ; source quench delay
RouteTabUnreach dw ROUTESLOTS dup (0) ; destination unreachable
RoutePutSlot dw 0
IpDesBuf BootpFrame <>
SnapHdr SnapStruc <>
IpHdr equ IpDesBuf.fIpStruc
MyIpNr equ IpDesBuf.fIpStruc.iIpSrc
;************************************************************************
;* SendUdpFind
;*
;* Input: BX = IP description buffer ptr (BX saved)
;* DX = addr of length prepended IP list to send to until reply
;* Output: Zero and CX = 0 if OK
;* non-zero and CX = errorcode if error
;* Destroys: AX, CX, DX, SI, DI, ES and flags
;************************************************************************
SendUdpFind proc near
mov [bx].dTimoutMsg,0 ; continue even if no reply
mov ah,2 ; do 2 turns over all IP #s
Send2ndTurn:
mov si,dx ; get IP list addr
lodsb ; # of IP numbers to al
inc si
SendNextIP:
mov di,[bx].dPtrIp
lea di,[di].iIpDst
movsw ; put next IP number
movsw
cmp ax,0101h ; last IP last turn?
jne Send2orMore
mov di,[bx].dTimOut2Msg
mov [bx].dTimoutMsg,di ; -yes, terminate if no reply
Send2orMore:
push ax
push dx
push si
mov ax,[bx].dPktLen
call SendUdpPkt ; send udp packet
pop si
pop dx
pop ax
jz SendUdpFindRet ; done if reply
dec al
jnz SendNextIP ; more IP numbers this turn?
mov di,[bx].dTick2Timeout ; -no, use longer timeout
mov [bx].dTickTimeout,di ; for 2nd turn
dec ah
jnz Send2ndTurn ; both turns done?
or cx,cx
SendUdpFindRet:
ret
SendUdpFind endp
;************************************************************************
;* SendUdpPkt
;*
;* Input: AX = IP data byte length (AX destroyed)
;* BX = IP description buffer ptr (BX saved)
;* Output: Zero and CX = 0 if OK
;* non-zero and CX = errorcode if error
;* Destroys: AX, CX, DX, SI, DI, ES and flags
;************************************************************************
SendUdpPkt proc near
push ax
xchg ah,al
mov di,[bx].dPtrUdp
mov [di].uUdpLen,ax ; fill in UDP total length
mov [di].uUdpXsum,ax ; ensure chksum is calculated
mov di,[bx].dPtrIp
mov [di].iIpProt,UDP_PROT ; set UDP protocol
call UdpChkSum ; calculate UDP checksum
pop ax
call SendIpPkt ; send UDP packet
ret
SendUdpPkt endp
;************************************************************************
;* SendIcmpPkt
;*
;* Input: BX = IP description buffer ptr (BX saved)
;* CX = IP data length
;* Output: Zero and CX = 0 if OK
;* non-zero and CX = errorcode if error
;* Destroys: AX, CX, DX, SI, DI, ES and flags
;************************************************************************
SendIcmpPkt proc near
push cx ; save length
call IcmpChkSum ; calculate icmp checksum
mov [bx].dWaitEvent,0 ; don't wait for answer
mov di,[bx].dPtrIp
mov [di].iIpProt,ICMP_PROT
pop ax ; restore length
; call SendIpPkt
; ret
SendIcmpPkt endp
;************************************************************************
;* SendIpPkt
;*
;* Input: AX = IP data byte length (AX destroyed)
;* BX = IP description buffer ptr (BX saved)
;* Output: Zero and CX = 0 if OK
;* non-zero and CX = errorcode if error
;* Destroys: AX, CX, DX, SI, DI, ES and flags
;************************************************************************
SendIpPkt proc near
call IPHdrLength ; calculate IP hdr length
mov dx,MyIpNr ; my IP # to IP src
mov [si].iIpSrc,dx
mov dx,MyIpNr+2
mov [si].iIpSrc+2,dx
add ax,cx ; add hdr length to data length
mov [bx].dPktLen,ax ; and save it
xchg ah,al
mov [si].iIpLen,ax ; fill in IP length
mov dx,IpIdCounter
mov [si].iIpId,dx ; unique id for frag reassembly
inc dx
mov IpIdCounter,dx
call IpChkSum ; calculate checksum
if RFCC
call Ageing ; clear unused table slots
endif ; RFCC
call PutPhysDst ; do we have HW dest addr?
jnz SendIpRet ; -no, ARP timed out
call PutPhysSrc ; put my HW src addr
add [bx].dPktLen,cx ; pkt length (HW addr part)
jmp short SendAndWait ; -yes, send packet
SendIpRet:
ret
SendIpPkt endp
;************************************************************************
;* SendAndWait
;* Input: BX = description buffer ptr (saved)
;* Output: Zero and CX = 0 if OK
;* non-zero and CX = errorcode if error
;* Destroys: AX, CX, DX, SI, DI, ES, flags
;************************************************************************
SendAndWait proc near
inc InSendAndW
mov si,[bx].dWaitEvent ; event to wait for
or si,si ; no event to wait for?
jz SendDontWait
not si
and Events,si ; clear this event bit
SendDontWait:
not si
if RFCC
; Do RFC1016 Source Quench Introduced Delay
mov ax,[bx].dSqDelay ; SQ delay (ms)
add ax,32 ; round up
mov cl,6
shr ax,cl ; convert ms to ticks
call CurrentTicks
add ax,cx ; time to send at
SendSqLoop:
call CurrentTicks
cmp cx,ax ; can we send it now?
jns SendNoSqDelay
call Something2Do ; - no, wait a while
jmp short SendSqLoop
SendNoSqDelay:
else
call CurrentTicks
endif ; RFCC
call SendRawPkt ; send packet part of buffer
mov di,[bx].dTickResend ; first resend time
mov ax,cx
add ax,di
mov dx,cx
add dx,[bx].dTickTimeout ; time out time
WaitLoop:
test Events,si ; got what we want?
jz SendChk
SendWaitOK:
xor cx,cx
SendWaitRet:
dec InSendAndW
or cx,cx
ret
SendChk:
call Something2Do ; anything else to do?
ChkTimeout:
call CurrentTicks
cmp cx,dx ; time out?
jns SendTimedout
cmp cx,ax ; time to resend?
js WaitLoop
shl di,1 ; double resend time
cmp di,30*18
jbe SendDouble
mov di,30*18 ; max 30 seconds
SendDouble:
add ax,di ; next resend time
call SendRawPkt ; send same packet again
jmp short WaitLoop
SendTimedout:
mov dx,[bx].dTimOutMsg
mov cx,SERRTIMOUT
or dx,dx ; if no timeout msg
jz SendWaitRet ; just return
mov ah,9 ; print error msg in dx
int 21h
mov al,04 ; error code 4
call Terminate
SendAndWait endp
;************************************************************************
;* SendRawPkt
;* Input: BX = description buffer ptr (saved)
;* Destroys: flags
;*
;* (The saving of all registers below is not needed for the Crynwr
;* collection of packet drivers, but as far as I understand the packet
;* driver specification other drivers may need it.)
;************************************************************************
SendRawPkt proc near
push dx
push cx
push bx
push ax
push si
push di
push bp
push es
mov si,[bx].dPtrPhys ; get start of packet
mov cx,[bx].dPktLen ; and its length
mov ah,4 ; send packet to
push ds ; packet driver
int_pkt
pop ds
pop es
pop bp
pop di
pop si
pop ax
pop bx
pop cx
jc BadPkt ; any errors?
pop dx
ret
BadPkt:
call print_error ; display explanation
mov al,03 ; error code 3
call Terminate
SendRawPkt endp
;************************************************************************
;* PutPhysSrc
;*
;* Input: BX = IP description buffer ptr (saved)
;* Output: HW src addr and IP prot type put into pkt
;* CX = phys header length
;* Destroys: CX, SI, DI, ES, flags
;************************************************************************
PutPhysSrc proc near
mov si,offset MyHwAd ; get my HW addr from ARP buf
mov di,[bx].dPtrPhys
mov cx,Hlen
add di,cx
push cs
pop es
rep movsb ; put my HW addr as src HW addr
test [bx].dSnap,1
jz PutPhysNotSnap
mov cx,[bx].dPktLen
add cx,8
xchg ch,cl
mov [di],cx
add di,2
mov cx,sProt-sDSAP
mov si,offset SnapHdr
rep movsb
PutPhysNotSnap:
mov cx,di
sub cx,[bx].dPtrPhys
add cx,2 ; physical header length
mov word ptr [di],0008h ; protocol type IP (0800)
ret
PutPhysSrc endp
;************************************************************************
;* PutPhysDst
;*
;* Input: BX = IP description buffer ptr (saved)
;* Output: Zero and CX = 0 if OK
;* non-zero and CX = errorcode if error
;* Destroys: AX, CX, DX, SI, DI, ES, flags
;************************************************************************
PutPhysDst proc near
mov ax,DefGwyNum ; # of default gwys we have
mov [bx].dGwys2Chk,al ; gwys still left to check
PutPhysAgain:
mov di,[bx].dPtrIp
mov al,[di].iIpTos ; get type of service
xor ah,ah
mov si,ax
mov dx,[di].iIpDst ; set dx,ax = dst IP #
mov ax,[di].iIpDst+2
call ArpPutHwDst ; do we know dst phys addr?
jz FoundArpEntry ; - yes, copied hw addr
call MyNetChk ; - no. Is dst on my net?
jz PutMynetArp ; - yes, don't use gwy
; and ARP dst
call UseGwy ; - no, use a gateway
jcxz PutArp ; destination unreachable?
jmp short PutPhysRet
PutMynetArp:
mov [bx].dGwys2Chk,1
PutArp:
call ArpPutHwDst ; have hw addr for this IP # ?
jz FoundArpEntry ; - yes, copied hw addr to pkt
call SendArpReq ; - no, arp for it
jz PutPhysAgain ; if reply, put in hw addr
call SwitchGwy ; else try next gwy
mov cx,SERRNOARP
dec [bx].dGwys2Chk ; any more default gwys?
jnz PutPhysAgain
PutPhysRet:
or cx,cx
FoundArpEntry:
ret
PutPhysDst endp
;************************************************************************
;* RouteFind
;*
;* Input: DX = first word of dst IP # (saved if not found)
;* AX = second word of dst IP # (saved if not found)
;* SI = IP type of service
;* Output: if found: zero and DI = route table index
;* DX = first word of gwy IP #
;* AX = second word of gwy IP #
;* CX = net/host unreachable code
;* Destroys: CX, DI, ES, flags
;************************************************************************
RouteFind proc near
mov di,offset RouteTabIpD2
mov cx,ROUTESLOTS
or cx,cx ; ensure non-zero flag
PushfDI
RouteFindNext: ; look for matching slot
repne scasw
jnz RouteFindRet
cmp dx,2*RouteSLOTS-2[di] ; does dst IP first part match?
jne RouteFindNext ; - no, look further
cmp si,4*RouteSLOTS-2[di] ; does dst tos match?
jne RouteFindNext ; - no, look further
sub di,offset RouteTabIpD2+2 ;- yes, compute slot index
mov dx,RouteTabIpG1[di] ; get gwy IP #
mov ax,RouteTabIpG2[di] ;
mov cx,RouteTabUnreach[di] ; get unreachable code
PopfEI
cmp di,di ; set zero flag
ret ; zero (found) return
RouteFindRet:
PopfEI
ret ; non zero (not found) return
RouteFind endp
;************************************************************************
;* MyNetChk
;*
;* Input: DX = first word of IP # (saved)
;* AX = second word of IP # (saved)
;* Output: zero if same net else non-zero
;* Destroys: flags
;************************************************************************
MyNetChk proc near
push ax
push dx
and dx,MyMask ; check if my net
cmp dx,MyNet
jne MyNetRet
and ax,MyMask+2
cmp ax,MyNet+2
MyNetRet:
pop dx
pop ax
ret
MyNetChk endp
;************************************************************************
;* UseGwy
;*
;* Input: DX = first word of destination IP #
;* AX = second word of destination IP #
;* SI = IP type of service
;* Output: DX = first word of gateway IP #
;* AX = second part of gateway IP #
;* CX = net/host unreachable code
;* Destroys: CX, SI, DI, ES, flags
;************************************************************************
UseGwy proc near
PushfDI
call RouteFind ; is dst in route tbl?
jz short UseGwyKnown ; - yes, have gwy IP #
; - no, use default gwy
dec cx
cmp dl,127 ; don't send to 127.x.x.x
je UseGwyRet
mov di,RoutePutSlot
add di,2 ; advance index two bytes
cmp di,ROUTESLOTS*2 ; at end of table?
jb UseRouteSlot
xor di,di ; - yes, wrap around
UseRouteSlot:
mov RoutePutSlot,di
mov RouteTabIpD1[di],dx ; put destination IP #
mov RouteTabIpD2[di],ax
mov RouteTabTos[di],si
mov si,DefGwyIndex
shl si,1
shl si,1
mov dx,DefGwys[si]
mov ax,DefGwys+2[si]
mov RouteTabIpG1[di],dx ; and default gwy IP #
mov RouteTabIpG2[di],ax ; into route table
call CurrentTicks
mov RouteTabTrRx[di],cx ; put current time
xor cx,cx ; initialize other fields
mov RouteTabUnreach[di],cx ; clear unreachable
mov RouteTabFlags[di],cx
mov RouteTabSqDelay[di],cx
or si,dx
or si,ax ; any non-zero gwy IP #?
jz UseGwyNone ; - yes
UseGwyKnown:
if RFCC
push cx
push ax
call CurrentTicks
mov RouteTabTrTx[di],cx ; transmit time
mov ax,RouteTabSqDelay[di] ; move sq delay to descriptor
mov [bx].dSqDelay,ax
dec ax ; any delay?
js UseNoSqDelay
mov ax,RouteTabTrSq[di] ; - yes
add ax,18 ; has one second passed
cmp ax,cx ; since we last decremented
jns UseNoSqDelay ; the delay value?
mov RouteTabTrSq[di],cx
dec RouteTabSqDelay[di] ; - yes, one millisecond off
UseNoSqDelay:
pop ax
pop cx
endif ; RFCC
UsegwyRet:
PopfEI
ret
UseGwyNone:
PopfEI
mov dx,offset NoGwyMsg
mov ah,9 ; - no, print error msg in dx
int 21h
mov al,08 ; error code 8
call Terminate
UseGwy endp
;************************************************************************
;* SwitchGwy
;*
;* Input: DX = first word of gateway IP # (saved)
;* AX = second word of gateway IP # (saved)
;* Destroys: CX, DI, ES, flags
;************************************************************************
SwitchGwy proc near
PushfDI
mov di,DefGwyIndex ; if current default gateway
shl di,1
shl di,1
cmp dx,DefGwys[di] ; is the one
jne SwitchNotThis
cmp ax,DefGwys+2[di] ; that failed
jne SwitchNotThis
shr di,1
shr di,1
inc di ; then switch to
cmp di,DefGwyNum
jb SwitchNextGwy
xor di,di
SwitchNextGwy:
mov DefGwyIndex,di ; next default gateway
SwitchNotThis:
PopfEI
mov di,offset RouteTabIpG2 ; remove failing gateway
mov cx,ROUTESLOTS ; from all route slots
PushfDI
SwitchRouteNext: ; look for matching slot
repne scasw
jnz SwitchGwyRet ; all entries searched
cmp dx,2*ROUTESLOTS-2[di] ; does gwy IP 2nd part match?
jne SwitchRouteNext ; - no, look further
sub di,offset RouteTabIpG2+2 ;- yes, clear this route
mov RouteTabIpD1[di],0
mov RouteTabIpD2[di],0
mov RouteTabIpG1[di],0
mov RouteTabIpG2[di],0
add di,offset RouteTabIpG2+2
jmp short SwitchRouteNext ; more routes using this gwy?
SwitchGwyRet:
PopfEI
ret
SwitchGwy endp
;************************************************************************
;* ChkSum
;* Input: SI = start addr
;* CX = # of bytes
;* Output: AX = 1-complement checksum
;* CX = partial checksum
;* SI = addr of next byte
;* Destroys: Flags
;************************************************************************
ChkSum proc near
if PINGCLIENT
test GenFlags,IS_386
jz ChkSum8086
.386
push edx ; save 386 registers
push eax
shr cx,1 ; divide by two, round down
pushf ; keep odd bit in carry
shr cx,1
pushf
xor edx,edx ; clear edx and carry
ChkLoop386:
lodsd
adc edx,eax ; add to previous running sum
loopw ChkLoop386
adc edx,0 ; add the last carry in again
mov eax,edx
shr eax,16
add dx,ax
adc dx,0
popf ; odd # of words?
jnc NotOddWords
lodsw
add dx,ax
adc dx,0
NotOddWords:
popf ; odd # of bytes?
jnc NotOddBytes
lodsb ; get that last byte
xor ah,ah ; clear carry and the high portion
add dx,ax ; add the last one in
adc dx,0 ; add the carry in, too
NotOddBytes:
pop eax
mov ax,dx
mov cx,dx
pop edx
not ax ; take one more 1-complement
ret
.8086
endif ; PINGCLIENT
ChkSum8086:
push dx
shr cx,1 ; divide by two, round down
pushf ; keep odd bit in carry
xor dx,dx ; clear dx and carry
ChkLoop:
lodsw
adc dx,ax ; add to previous running sum
loop ChkLoop
adc dx,0 ; add the last carry in again
popf ; odd # of bytes?
jnc NotOdd
lodsb ; get that last byte
xor ah,ah ; clear carry and the high portion
add dx,ax ; add the last one in
adc dx,0 ; add the carry in, too
NotOdd:
mov ax,dx
mov cx,dx
pop dx
not ax ; take one more 1-complement
ret
ChkSum endp
;************************************************************************
;* UdpChkSum (both for generate and check!)
;*
;* Input: BX = IP description buffer ptr (saved)
;* Output: Zero if OK; checksum filled in
;* SI = addr of next byte
;* DI = IP Ptr
;* Destroys: AX, CX, DX, SI, DI, flags
;************************************************************************
UdpChkSum proc near
mov si,[bx].dPtrIp
mov di,[bx].dPtrUdp
xor cx,cx ; save ttl for pseudo hdr
xchg cl,[si].iIpTtl ; usage
push cx
xor dx,dx
xchg dx,[di].uUdpXsum ; save and clear checksum
mov cx,[di].uUdpLen ; save UDP length
mov [si].iIpXsum,cx
xchg ch,cl
mov ax,di
add ax,cx
or dx,dx ; is there a checksum?
mov si,ax ; - no, not available/wanted
jz UdpNoSum ; but set si to end of data
push cx ; - yes
mov cx,12 ; checksum pseudo hdr
mov si,[bx].dPtrIp
add si,iIpTtl
call ChkSum
mov [di].uUdpXsum,cx ; move partial checksum
; into udp hdr
pop cx ; checksum udp hdr+data
mov si,di
call ChkSum
jnz UdpNotZero ; checksum is zero?
not ax ; - yes, make it FFFFh
UdpNotZero:
mov [di].uUdpXsum,ax
cmp ax,dx ; does checksums match?
UdpNoSum:
pop cx
mov di,[bx].dPtrIp
mov [di].iIpTtl,cl ; restore ttl
ret
UdpChkSum endp
;************************************************************************
;* IpHdrLength
;*
;* Input: BX = IP description buffer ptr (saved)
;* Output: CX = IP header byte length
;* SI = pointer to IP header
;* Destroys: SI, flags
;************************************************************************
IpHdrLength proc near
mov si,[bx].dPtrIp
mov cx,[si] ; get version+length byte
and cx,0fh ; length (32 bit words)
shl cx,1 ; convert to
shl cx,1 ; byte length
ret
IpHdrLength endp
;************************************************************************
;* IpChkSum (both for generate and check!)
;*
;* Input: BX = IP description buffer ptr (saved)
;* Output: Zero if OK; checksum filled in
;* Destroys: AX, CX, DX, SI, DI, flags
;************************************************************************
IpChkSum proc near
xor dx,dx
mov di,[bx].dPtrIp
xchg dx,[di].iIpXsum ; save and clear checksum
call IpHdrLength
call ChkSum ; calculate new checksum
mov [di].iIpXsum,ax
cmp ax,dx ; does checksums match?
ret
IpChkSum endp
;************************************************************************
;* IcmpChkSum (both for generate and check!)
;*
;* Input: BX = IP description buffer ptr (saved)
;* CX = IP data length
;* Output: Zero if OK; checksum filled in
;* Destroys: AX, CX, DX, SI, DI, flags
;************************************************************************
IcmpChkSum proc near
xor dx,dx
mov di,[bx].dPtrUdp
xchg dx,[di].uIcmpXsum ; save and clear checksum
mov si,di
call ChkSum ; calculate new checksum
mov [di].uIcmpXsum,ax
cmp ax,dx ; does checksums match?
ret
IcmpChkSum endp
;************************************************************************
;* CurrentTicks
;* Output: CX = low word of ticks (1/18 second) counter
;* Destroys: CX, ES
;************************************************************************
CurrentTicks proc near
mov cx,040h ; DOS data segment
mov es,cx
mov cx,es:6ch ; get low word of ticks cntr
push cs
pop es
ret
CurrentTicks endp
if RFCC
;************************************************************************
;* Ageing of ARP and Route tables
;*
;* Destroys: AX, CX, DX, SI, DI, ES, flags
;************************************************************************
AgeNext dw 0 ; time to check slots
Ageing proc near
PushfDI
call CurrentTicks ; get current ticks value
cmp cx,AgeNext
jns AgeNow ; time to do ageing?
PopfEI
ret
AgeNow:
mov di,cx
mov dx,cx
add cx,2*18 ; chk next 2 seconds from now
mov AgeNext,cx
sub dx,65*18 ; clear what is older than 1 min
mov cx,ARPSLOTS-3
mov si,offset ArpTabTr+6
AgeArpLoop:
and word ptr [si+2*ARPSLOTS],not SQ_UPDATED ; clr every 2 s
lodsw
cmp ax,dx
jns AgeArpYoung ; not touched in a minute?
sub si,offset ArpTabTr+2
push cx
push di
push dx
mov dx,ArpTabIp1[si]
mov ax,ArpTabIp2[si]
call switchGwy ; in case it's a gwy: switch
pop dx
pop di
pop cx
xor ax,ax
mov ArpTabTr[si],di ; set current time
mov ArpTabIp1[si],ax ; clear old entries
mov ArpTabIp2[si],ax
mov ArpTabHw1[si],ax
mov ArpTabHw2[si],ax
mov ArpTabHw3[si],ax
add si,offset ArpTabTr+2
AgeArpYoung:
loop AgeArpLoop
PopfEI
mov cx,ROUTESLOTS
mov si,offset RouteTabTrRx
PushfDI
AgeRouteLoop:
and word ptr [si+2*ROUTESLOTS],not SQ_UPDATED ; clr every 2 s
lodsw
cmp ax,dx ; old slot?
jns AgeRouteYoung
sub si,offset RouteTabTrRx+2
mov RouteTabTrRx[si],di
xor ax,ax
cmp RouteTabUnreach[si],ax ; any error code?
jne AgeRouteUnr
cmp dx,RouteTabTrTx[si] ; - no. Sent anything lately?
jns AgeRouteEnd ; - no, that's why
mov RouteTabUnreach[si],SERRNOTRAF ;- yes, somebody is dead
jmp short AgeRouteEnd
AgeRouteUnr: ; - yes, remove slot
mov RouteTabIpD1[si],ax
mov RouteTabIpD2[si],ax
mov RouteTabIpG1[si],ax
mov RouteTabIpG2[si],ax
AgeRouteEnd:
add si,offset RouteTabTrRx+2
AgeRouteYoung:
loop AgeRouteLoop
PopfEI
call AgeFrags ; release old fragments
ret
Ageing endp
;************************************************************************
;* VerifyIpHdr (RFC1122 requirements)
;*
;* verify IP dst = me (or bcast), process IP options, verify IPver=4,
;* verify IP src not bcast, set timer value in ArpTab and RouteTab.
;* Process IP fragments.
;************************************************************************
holeStruc struc
holeNext dw 0
holeFirst dw 0
holeLast dw 0
HOLEDESCRLEN equ $-holeNext
holeStruc ends
k18 db 18
VerifyIpHdr proc near
push si
push di
mov al,[di].iIpVerHlen
and al,0f0h
cmp al,040h ; IP version 4?
jne VerifyErr1
mov di,[bx].dPtrPhys
mov si,[di]
mov dx,[di+2]
mov ax,[di+4]
call ArpFindHw ; find Hw Dst arp index
mov [bx].dIdxHwDst,di ; 0 = bcast, 4 = me
cmp MyIpNr,0
je VerifyMeNotInArp
cmp di,ARPMYIDX ; is Hw addr to me or bcats?
ja VerifyErr1
VerifyMeNotInArp:
mov di,[bx].dPtrPhys
add di,Hlen ; get physical src addr
mov si,[di]
mov dx,[di+2]
mov ax,[di+4]
call ArpFindHw ; is Hw Src in arp table?
jz VerifyChkBcast ; - yes
cmp [bx].dIdxHwDst,ARPMYIDX ; - no. Addressed to me?
jne VerifyIpDst ;
pop di ; - yes
push di
mov dx,[di].iIpSrc
mov ax,[di].iIpSrc+2
call MyNetChk ; if he is on my net
jnz VerifyIpDst
mov si,[bx].dPtrPhys
add si,Hlen
call ArpPutNew ; add him to arp table
jmp short VerifyIpDst
VerifyErr1: jmp short VerifyErr
VerifyChkBcast:
cmp di,ARPMYIDX ; from me or broadcast?
jbe VerifyErr ; - yes, ignore packet
call CurrentTicks ; get current ticks value
mov ArpTabTr[di],cx
VerifyIpDst:
cmp MyIpNr,0
je VerifyIpUnknown
pop di
push di
mov dx,[di].iIpDst ; check IP dst
mov ax,[di].iIpDst+2
call ArpFindIp
mov [bx].dIdxIpDst,di
cmp di,ARPMYIDX ; is it to me or broadcast?
ja VerifyErr ; - no, ignore packet
VerifyIpUnknown:
pop di
push di
mov dx,[di].iIpSrc
mov ax,[di].iIpSrc+2
call ArpFindIp
jnz VerifyNoArp
cmp di,ARPMYIDX ; from IP broadcast?
jb VerifyErr ; -yes, ignore packet
VerifyOK:
call AgeFrags ; release old reassembly bufs
pop di
push di
test [di].iIpFlFrag,0ff3fh ; is this a fragment?
jnz VerifyFrag
clc ; - no, use as is
VerifyRet:
pop di
pop si
ret
VerifyNoArp:
pop di
push di
mov cl,[di].iIpTos
xor ch,ch
mov si,cx
call RouteFind ; is he in route table?
jnz VerifyNoRoute
call CurrentTicks
mov RouteTabTrRx[di],cx ; note we've got pkts from him
VerifyNoRoute:
jmp short VerifyOK
FragAddAndErr:
mov si,offset FragList
call AddToList
VerifyFragErr:
mov bx,bp
VerifyErr:
call BufRelease
VerifyKeep:
stc
jmp short VerifyRet
VerifyFrag: ; RFC 815 fragment reassembly:
mov bp,bx ; addr of fragment buffer
mov dx,[di].iIpSrc ; get IP # / IP id / IP prot
mov ax,[di].iIpSrc+2
mov si,[di].iIpId
mov cx,Fraglist.lBufsAvail
mov ch,[di].iIpProt
FragLook4Buf:
mov di,offset FragList
call GetFromList
jz FragEarliest ; any reassembly buffers?
mov di,[bx].dPtrIp ; match IP#/Id/Prot
cmp dx,[di].iIpSrc
jne FragNextBuf
cmp ax,[di].iIpSrc+2
jne FragNextBuf
cmp si,[di].iIpId
jne FragNextBuf
cmp ch,[di].iIpProt
je FragBufFound
FragNextBuf:
push si ; irrelevant buf, put it back
mov si,offset FragList
call AddToList
pop si
dec cl
jnz FragLook4Buf
FragEarliest:
call FragFirstLast ; compute addr of fragment
or ax,ax ; first part earliest?
jnz FragOffset
mov bx,bp
mov di,[bx].dPtrUdp
add di,dx
cmp [bp].dHomeList,offset FreeBufs ; and a big buffer?
je FragFirstHole ; - yes, no extra buffer needed
FragOffset:
call BufAlloc ; - no, create empty buffer
jz VerifyFragErr
add di,2+2*EADDR_LEN
mov [bx].dPtrIp,di
mov si,[bp].dPtrIP
mov cx,[bp].dPtrUdp ; copy IP header
sub cx,si
call movemem
mov [bx].dPtrUdp,di
FragFirstHole:
mov [di].holeNext,0 ; create first hole descriptor
mov [di].holeFirst,0
mov [di].holeLast,GIANT
mov [bx].dPtrFrag,di
add di,HOLEDESCRLEN ; mark end of info
mov [bx].dPktEnd,di
FragBufFound:
call FragFirstLast ; compute addr of fragment
lea di,[bx].dPtrFrag
FragNextHole: ; 1. select next hole descr
mov si,di
mov di,[si].holeNext
or di,di ; any more descriptors?
jz FragEndHoles
cmp ax,[di].holeLast ; 2. frag.first > hole.last?
jae FragNextHole
cmp dx,[di].holeFirst ; 3. frag.last < hole.first?
jbe FragNextHole
mov cx,[di].holeNext ; 4. delete current hole descr
mov [si].holeNext,cx
mov cx,[di].holeLast
cmp ax,[di].holeFirst ; 5. frag.first > hole.first?
jbe FragNoNew1
mov [si].holeNext,di ; create new hole descr
mov [di].holeLast,ax
FragNoNew1:
mov si,[bp].dPtrIp ; 6. if frag.more
test [si].iIpFlFrag,0020h
jz FragLastFrag
cmp dx,cx ; and frag.last < hole.last?
jae FragNextHole
mov si,[bx].dPtrUdp
add si,dx
mov [si].holeFirst,dx ; create new hole descr
mov [si].holeLast,cx
mov cx,[bx].dPtrFrag
mov [si].holeNext,cx
mov [bx].dPtrFrag,si
add si,HOLEDESCRLEN
cmp si,[bx].dPktEnd
jbe FragNextHole
FragPktEnd:
mov [bx].dPktEnd,si
jmp short FragNextHole
FragLastFrag: ; when last frag
mov si,[bx].dPtrUdp ; prepare IP length
add si,dx
jmp short FragPktEnd
FragEndHoles: ; 8. copy data to assembly buf
cmp bx,bp ; do we need to copy?
je FragTimeUpd
or ax,ax ; if first frag
jnz FragNotFirst
mov si,[bx].dPtrUdp ; retain this IP header
mov di,[bp].dPtrUdp ; and copy assembled data
mov cx,[bx].dPktEnd ; to frag buffer
sub cx,si
add si,dx ; skip over first fragment
add di,dx
sub cx,dx
call movemem
mov [bp].dPktEnd,di
mov cx,[bx].dPtrFrag
mov [bp].dPtrFrag,cx
xchg bx,bp ; and switch buffers
mov cx,di
sub cx,si ; hole ptr adjustment
lea di,[bx].dPtrFrag
FragUpdLoop:
mov si,di
mov di,[si].holeNext
or di,di
jz FragRelBuf ; end of hole list
add di,cx
mov [si].holeNext,di ; new pointer address
jmp short FragUpdLoop
FragNotFirst:
mov si,[bp].dPtrUdp ; copy this frag to asm buf
mov cx,dx
sub cx,ax
mov di,[bx].dPtrUdp
add di,ax
call movemem
FragRelBuf:
push bx ; release frag buf
mov bx,bp
call BufRelease
pop bx
FragTimeUpd:
call CurrentTicks ; update timer entry
mov di,[bx].dPtrIp
mov al,[di].iIpTtl
mul k18
add cx,ax
mov [bx].dTickTimeout,cx
mov di,[bx].dPtrIp
mov si,[bx].dPtrUdp
cmp [bx].dPtrFrag,0 ; any holes?
jne FragKeep ; - yes, wait for more pkts
mov cx,[bx].dPktEnd ; - no
mov ax,cx ; compute IP length
sub cx,[bx].dPtrIp
xchg ch,cl
mov [di].iIpLen,cx
sub ax,[bx].dPtrPhys
mov [bx].dPktLen,ax ; and packet length
add sp,4 ; pop si and pop di
ret
FragKeep:
mov si,offset FragList ; keep buf a while
call AddToList
jmp VerifyKeep
VerifyIpHdr endp
;************************************************************************
;* FragFirstLast
;************************************************************************
FragFirstLast proc near
mov di,[bp].dPtrIp ; compute frag.first
mov ax,[di].iIpFlFrag
xchg ah,al
and ax,1fffh
shl ax,1
shl ax,1
shl ax,1
mov dx,[di].iIpLen ; compute frag.last (+1)
xchg dh,dl
add dx,[bp].dPtrIp
sub dx,[bp].dPtrUdp
add dx,ax
cmp dx,GIANT-IPHDRLEN-HWHDRLEN ; fits in buffer?
ja FragTooBig
ret
FragTooBig:
add sp,2 ; remove return addr from stack
jmp FragAddAndErr
FragFirstLast endp
;************************************************************************
;* AgeFrags
;************************************************************************
AgeFragsNext dw 0
AgeFrags proc near
call CurrentTicks
cmp cx,AgeFragsNext
jns AgeFragsNow ; time to age yet?
ret
AgeFragsNow:
mov dx,cx
add cx,2*18 ; check next in 2 seconds
mov AgeFragsNext,cx
push bx
PushfDI
mov cx,Fraglist.lBufsAvail
AgeLook4Buf:
mov di,offset FragList
call GetFromList
jz AgeNoMoreFrags ; any reassembly buffers?
mov si,offset FragList
cmp dx,[bx].dTickTimeout
js AgenextBuf ; too old?
; - no, put it back
mov si,[bx].dHomeList ; - yes, release it
AgeNextBuf:
call AddToList
dec cl
jnz AgeLook4Buf ; any more reassembly bufs?
AgeNoMoreFrags:
PopfEI
pop bx
ret
AgeFrags endp
endif ; RFCC
;************************************************************************
;* SwitchIpDst
;************************************************************************
SwitchIpDst proc near
mov si,[bx].dPtrIp
SwitchIpDstB:
mov dx,[si].iIpSrc ; mov his IP # to IP dst
mov di,[bx].dPtrIp
mov [di].iIpDst,dx
mov dx,[si].iIpSrc+2
mov [di].iIpDst+2,dx
ret
SwitchIpDst endp
;************************************************************************
;* InitIp
;************************************************************************
InitIp proc near
pushf
pop ax
or ax,7000h ;the 386 lets us set these bits
push ax
popf
pushf
pop ax
test ax,7000h ;did the bits get set?
jz IsNot386 ;no.
or GenFlags,IS_386 ;yes, use a 386-optimized code
IsNot386:
push ds
mov IpDesBuf.dPtrPhys,offset IpDesBuf.fHwStruc ; *test*
mov IpDesBuf.dPtrIp,offset IpDesBuf.fIpStruc
mov IpDesBuf.dPtrUdp,offset IpDesBuf.fBotStruc
mov ax,1ffh ;driver_info
int_pkt
pop ds
call fatal_error
mov ah,2 ;access all packets.
mov al,ch ;their class from driver_info().
mov bx,dx ;their type from driver_info().
mov dl,cl ;their number from driver_info().
mov cx,2 ;type length of two.
mov si,offset IpDesBuf.fHwStruc.hProtType
push cs ;es:di -> our receiver.
pop es
mov di,offset IpRecv
push ds
int_pkt
pop ds
call fatal_error
mov IpHandle,ax
ret
InitIp endp
;************************************************************************
;* EndProtocol
;************************************************************************
EndProtocol proc near
mov ah,3 ; release handle in bx
push ds
int_pkt
pop ds
call print_error
ret
EndProtocol endp
;************************************************************************
;* Terminate
;************************************************************************
Terminate proc near
pop bx ; remove return addr fr stack
push ax
cld
push cs
push cs
pop ds
pop es
sti
mov bx,IpHandle ; release ARP and IP handles
call EndProtocol
mov bx,ArpHandle
call EndProtocol
if PINGCLIENT
cmp EchoTarget,0
jz TermNoPing
call RestoreTimer
TermNoPing:
endif ; PINGCLIENT
pop ax
push ax
or al,al ; any errors?
jz termnorm
cmp EnoughWord,HAVE_MYIPNR ; clock errors?
je termnorm
mov dx,offset MsgNotSet ; display "clock not set"
mov ah,9
int 21h
termnorm:
pop ax
push ax
add al,'0'
mov MsgTermNr,al ; show error # in end line
mov si,offset MyHwAd
mov di,offset MsgTermHw
call PutHwNum ; put my HW addr
mov si,offset MyIpNr
mov di,offset MsgMyIp
call PutIpNum ; put my IP #
mov dx,offset MsgTerm ; End of PDCLKSET msg
mov ah,9
int 21h
pop ax ; error code
mov ah,4ch
int 21h ; terminate program
Terminate endp
;************************************************************************
;* IP receiver *
;************************************************************************
IpRecv:
pushf
push ds ; set segment registers
mov dx,cs
mov ds,dx
mov es,dx
cld
or ax,ax ; first or second call?
jne IpRecv_1 ; - second, we've got data
; - first, they want a buf
cmp cx,GIANT ; packet too long?
ja IpRecTooBig
if PINGCLIENT
cmp cx,BUFBODYSML
ja IpRecBig
call BufAlSml
jz IpRecBig
pop ds
popf
retf
IpRecBig:
endif ; PINGCLIENT
call BufAlloc ; get a receive buffer
jz IpRecNoBuf
IpRecRet0:
pop ds
popf
retf
if DEBUG
DbgIpRecv:
or GenFlags,DBGINTERR
endif ; DEBUG
IpRecNoBuf:
if PINGCLIENT
inc EchoDrop
endif ; PINGCLIENT
IpRecTooBig:
xor di,di ; no buffer available
mov es,di
jmp short IpRecRet0
IpRecv_1:
; If I understand PC interrupt handling correctly, the following stackswitch
; and interrupt enabling should not kill multiprocess reentrancy.
cli ; switch to our
mov word ptr SaveSP,sp ; interrupt stack
mov word ptr SaveSS,ss
mov sp,offset StackEnd
mov ss,MySegm
sti ; allow interrupts
if DEBUG
dec DbgIntCnt ; double interrupt?
jnz DbgIpRecv
endif ; DEBUG
call BuildRecDescr ; calculate pointers etc
call IpChkSum ; only accept a correct
jne IpRecRet ; IP checksum
mov [bx].dPtrUdp,si
if RFCC
call VerifyIpHdr ; verify and process IP hdr
jc IpRecKeepBuf
endif ; RFCC
cmp [di].iIpProt,ICMP_PROT ; ICMP protocol?
jne IpNotIcmp
jmp IpRecIcmp
IpNotIcmp:
cmp [di].iIpProt,UDP_PROT ; UDP protocol?
jne IpProtUnr
call UdpChkSum ; if available, test
jne IpRecRet ; UDP checksum
cmp si,[bx].dPktEnd ; still within packet limit?
jbe IpRecUdp
IpRecRet:
call BufRelease ; release receive buffer
IPRecKeepBuf:
if DEBUG
inc DbgIntCnt
endif ; DEBUG
cli ; restore previous stack
mov sp, word ptr SaveSP
mov ss, word ptr SaveSS
pop ds
popf
retf
IpPortUnr:
mov ah,3 ; port unreachable
jmp short IpUnr
IpProtUnr:
mov ah,2 ; protocol unreachable
IpUnr:
if RFCC
mov al,3 ; destination unreachable
cmp [bx].dIdxHwDst,ARPMYIDX ; was it specifically to me?
jne IpRecRet
mov bp,bx
call BufAlloc
jz UnrEnd
call MakeSendDescr
mov si,[bp].dPtrIp ; copy IP header
mov cx,[bp].dPtrUdp
add cx,8 ; + 8 bytes
sub cx,si
call SwitchIpDstB ; return to sender
mov di,[bx].dPtrUdp
mov [di].uIcmpTypecode,ax ; set type and code
add di,8
call movemem
sub di,[bx].dPtrUdp
mov [bx].dPktLen,di ; set IP data length
mov si,offset IcmpToDo ; put buf on the ICMP send list
call AddToList
UnrEnd:
mov bx,bp
endif ; RFCC
jmp IpRecRet
IpRecUdp:
mov [bx].dPktEnd,si ; end of logical pkt
mov di,[bx].dPtrUdp
cmp word ptr [di].uUdpSrc,2500h ; Src port 0025 = 37 ?
je IpRecvTime ; - must be time reply
if TBLBUILD or PINGCLIENT
cmp word ptr [di].uUdpSrc,3500h ; Name server (53)?
jne $+5
jmp IpRecvName
endif ; TBLBUILD or PINGCLIENT
cmp word ptr [di].uUdpSrc,4300h ; Src port 0043 = 67
jne IpPortUnr
cmp word ptr [di].uUdpDst,4400h ; Dst port 0044 = 68
jne IpPortUnr
cmp byte ptr [di].uBotOp,2 ; bootp reply?
jne IpRecRet
IpRecBootp:
push di ; - must be bootp reply
lea si,[di].uBotCliHwAd
mov di,offset MyHwAd
mov cx,Hlen
repe cmpsb ; our Ethernet addr?
pop di
jne IpRecRet2
mov ax,word ptr IpDesBuf.fBotStruc.uBotXid
cmp ax,word ptr [di].uBotXid ; our random id?
jne IpRecRet2
mov ax,word ptr IpDesBuf.fBotStruc.uBotXid+2
cmp ax,word ptr [di].uBotXid+2
jne IpRecRet2
; yes, it's about me!
mov dx,[di].uBotGwyIp ; saves an ARP request
mov ax,[di].uBotGwyIp+2 ; in many cases
mov si,[bx].dPtrPhys
add si,Hlen
call ArpPutNew
test Events,GOT_BOOTP ; if first answer
jnz IpRecRet2 ; save bootp answer
mov AdrBootpReply,bx ; for further study
or Events,GOT_BOOTP
jmp IpRecKeepBuf
IpRecvTime:
test Events,GOT_TIMEREPLY ; already got reply?
jnz IpRecRet2
mov ax,[di].uUdpData ; save seconds
mov cTime,ax ; since year 1900
mov ax,[di].uUdpData+2
mov cTime+2,ax
mov di,[bx].dPtrIp ; save who was answering
mov dx,[di].iIpSrc
mov ax,[di].iIpSrc+2
mov RespondingIpNr,dx
mov RespondingIpNr+2,ax
or Events,GOT_TIMEREPLY
IpRecRet2:
jmp IpRecRet
if TBLBUILD or PINGCLIENT
IpRecvName:
mov si,offset NameToDo ; process nameserver reply
call AddToList
jmp IpRecKeepBuf
endif ; TBLBUILD or PINGCLIENT
IpRecIcmp:
mov cx,[di].iIpLen ; calculate IP data length
xchg ch,cl
add cx,di
sub cx,si
mov [bx].dPktLen,cx ; save IP data length
call SwitchIpDst ; in case we want to return it
call IcmpChkSum ; valid ICMP checksum?
jne IpRecRet2
mov si,[bx].dPtrUdp ; point to ICMP header
mov cx,[si].uIcmpTypecode ; get type and code
mov dx,[si].uIcmpIpHdr.iIpDst ; get original IP hdr
mov ax,[si].uIcmpIpHdr.iIpDst+2 ; dst IP #
if PINGCLIENT
cmp cl,0 ; echo reply?
jne IpNotEchoReply
call EchoCalc
jmp IpRecRet
endif ; PINGCLIENT
if RFCC
IpNotEchoReply:
cmp cl,8 ; echo request?
jne IpNotEchoReq
cmp [bx].dIdxHwDst,ARPMYIDX ; broadcast?
jb IpRecRet2 ; - yes, don't echo
mov byte ptr [si].uIcmpTypecode,0 ; put echo reply value
mov si,offset IcmpToDo ; put buf on the ICMP send list
call AddToList
jmp IpRecKeepBuf
IpNotEchoReq:
endif ; RFCC
cmp cx,11 ; TTL exceeded?
je IpIcmpUnreach
cmp cl,3 ; unreachable
jne IpNotUnreach
cmp ch,12 ; net or host unreachable?
ja IpIcmpRet2
cmp ch,6
ja IpIcmpUnreach
cmp ch,1
ja IpIcmpRet2
IpIcmpUnreach: ; codes 0 - 1, 6 - 12 go here
PushfDI
push si
mov cl,[si].uIcmpIpHdr.iIpTos
xor ch,ch
mov si,cx
call RouteFind ; this host in route table?
pop si
jnz IpIcmpUnfound
mov ah,byte ptr [si].uIcmpTypeCode+1 ; icmp code
xor al,al ;*test
inc ah ; ensure non zero error code
mov RouteTabUnreach[di],ax ; mark it unreachable
call CurrentTicks ; get current ticks value
mov RouteTabTrRx[di],cx ; set timer
IpIcmpUnfound:
PopfEI
IpIcmpRet2:
jmp IpIcmpRet
IpNotUnreach:
if RFCC
cmp cl,4 ; source quench
jne IpIcmpNotQuench
PushfDI
push si
mov cl,[si].uIcmpIpHdr.iIpTos
xor ch,ch
mov si,cx
call RouteFind ; this host in route table?
pop si
jnz IpIcmpNotRoute
mov dx,RouteTabFlags[di]
or RouteTabFlags[di],SQ_UPDATED
lea si,RouteTabTrSq[di]
lea di,RouteTabSqDelay[di]
jmp short IpIcmpSq
IpIcmpNotRoute:
call ArpFindIp
jnz IpIcmpSqEnd
mov dx,ArpTabFlags[di]
or ArpTabFlags[di],SQ_UPDATED
lea si,ArpTabTrSq[di]
lea di,ArpTabSqDelay[di]
IpIcmpSq:
mov ax,[di] ; get current sq delay
or ax,ax
jnz IpIcmpAddDelay
call CurrentTicks
mov [si],cx ; initialize sq timer
mov ax,150*64/55 ; initial sq delay 178 ms
IpIcmpAddDelay:
add ax,28*64/55 ; increase delay by 28 ms
test dx,SQ_UPDATED ; unless already done in
jnz IpIcmpSqEnd ; the last two seconds
mov [di],ax
IpIcmpSqEnd:
PopfEI
jmp short IpIcmpRet
IpIcmpNotQuench:
endif ; RFCC
cmp cl,5 ; redirect
jne IpNotRedirect
PushfDI
push si
mov cl,[si].uIcmpIpHdr.iIpTos
xor ch,ch
mov si,cx
call RouteFind ; this host in route table?
pop si
jnz IpIcmpDisfound
mov dx,RouteTabIpG1[di] ; icmp from the gwy used?
mov ax,RouteTabIpG2[di]
mov cx,di
mov di,[bx].dPtrIp
cmp dx,[di].iIpSrc
jne IpIcmpDisfound
cmp ax,[di].iIpSrc+2
jne IpIcmpDisfound
mov di,cx
mov dx,[si].uIcmpData ; new gateway IP #
mov ax,[si].uIcmpData+2
call MyNetChk ; is he on my net?
jnz IpIcmpDisfound
mov RouteTabIpG1[di],dx ; put it into route table
mov RouteTabIpG2[di],ax
IpIcmpDisfound:
PopfEI
jmp short IpIcmpRet
IpNotRedirect:
IpIcmpRet:
jmp IpRecRet
;************************************************************************
;* MakeMynet
;************************************************************************
MakeMynet proc near
mov dx,MyIpNr
mov ax,MyIpNr+2
mov ArpTabIp1+4,dx ; third arp slot = me
mov ArpTabIp2+4,ax
mov si,offset MyHwAd
call ArpPutNew
mov si,MyMask
mov di,MyMask+2
and dx,si ; calculate network #
and ax,di
mov MyNet,dx
mov MyNet+2,ax
not si ; second arp slot =
not di ; subnet broadcast
or dx,si
or ax,di
mov ArpTabIp1+2,dx
mov ArpTabIp2+2,ax
ret
MakeMynet endp
;************************************************************************
;* ValidateIpNr
;************************************************************************
ValidateIpNr proc near
call BufAlloc
mov [bx].dTimOutMsg,0 ; we SHOULD get no answer
mov [bx].dTickTimeout,10 ; give them half a second
mov dx,MyIpNr
mov ax,MyIpNr+2
call SendArpReq ; send arp to our Ip #
call BufRelease
jz ValConflict ; someone else has our IP # ?
ret ; - no, return
ValConflict: ; - yes, error termination
call ArpFindIp
mov cl,3
shl di,cl
lea si,ArpTabHwAdr[di] ; get HW addr of arp reply
mov di,offset OccupiedHw
call PutHwNum ; put offending HW addr
mov dx,offset OccupiedMsg ; display IP occupied msg
mov ah,9
int 21h
mov al,09 ; error code 9
call terminate
ValidateIpNr endp
;************************************************************************
;* DoBootpPkt
;************************************************************************
DoBootpPkt proc near
call CurrentTicks ; get current ticks value
mov IpDesBuf.fBotStruc.uBotXid,cx ; as transaction id
if RFCC
add cx,2*18 ; initialize ageing
mov AgeNext,cx
mov AgeFragsNext,cx
endif ; RFCC
mov al,byte ptr ArpBuf.iArpHtype+1
mov IpDesBuf.fBotStruc.uBotHtype,al ; put my HW type
mov si,offset MyHwAd
mov di,offset IpDesBuf.fBotStruc.uBotCliHwAd
push cs
pop es
mov cx,Hlen
mov IpDesBuf.fBotStruc.uBotHlen,cl
rep movsb ; copy my HW addr
mov bx,offset IpDesBuf ; frame to send
call MakeSendDescr
mov [bx].dWaitEvent,GOT_BOOTP ; event to wait for
mov [bx].dTimOutMsg,offset NoBotReplyMsg ; error msg
mov ax,BpDataLen+UDPHDRLEN ; bootp pkt length
call SendUdpPkt ; send bootp request
ret
DoBootpPkt endp
;************************************************************************
;* InterpBootp according to RFC 1084 and RFC1048
;************************************************************************
InterpBootp proc near
mov bx,AdrBootpReply
mov di,[bx].dPtrUdp
mov dx,[di].uBotYourIp ; mov my IP #
mov MyIpNr,dx ; to IP buf
mov ax,[di].uBotYourIp+2
mov MyIpNr+2,ax
or Flagword,HAVE_MYIPNR ; note what we've got
cmp word ptr [di].uBotMagNum,8263h ; RFC 1084 type of
jne VendEnd ; vendor area?
cmp word ptr [di].uBotMagNum+2,6353h
jne VendEnd
lea si,[di].uBotVend ; start of "vendor area"
lea bp,[si]+64-4 ; end of "vendor area"
push cs
pop es
VendLoop:
cmp si,bp ; beyond vendor area?
jb VendNext
VendEnd:
call BufRelease ; release bootp reply buf
ret
VendNext:
lodsb ; get field type:
cmp al,0 ; filler
je VendLoop
cmp al,1 ; netmask
jne NotMask
mov di,offset MyMask
call Xtract4Bytes
jmp short VendLoop
NotMask:
cmp al,2 ; zone/time (?) offset
jne NotTimeOffs
test Flagword,HAVE_TIMEOFFSET
jnz VendDefault
mov di,offset tzoffset
call Xtract4Bytes
or Flagword,HAVE_TIMEOFFSET
jmp short VendLoop
NotTimeOffs:
cmp al,3 ; default gateways
jne NotDefGwys
mov di,offset DefGwys
mov cx,MAXDEFGWYS
mov ax,DefGwyNum
call XtractIpNums
add DefGwyNum,cx
jmp short VendLoop
NotDefGwys:
cmp al,4 ; time servers
jne NotTimeserv
or Flagword,HAVE_TIMESERVER
mov di,offset TimeServIpNr
mov cx,MAXTSERVS
mov ax,TservNum
call XtractIpNums
add TservNum,cx
jmp short VendLoop
NotTimeserv:
if TBLBUILD or PINGCLIENT
cmp al,6 ; default nameservers
jne NotDefNS
mov di,offset DefNS
mov cx,MAXDEFNS
mov ax,DefNSnum
call XtractIpNums
add DefNSnum,cx
jmp short VendLoop
NotDefNS:
endif ; TBLBUILD or PINGCLIENT
cmp al,0ffh ; end
je VendEnd
VendDefault: ; everything else
lodsb
xor ah,ah
add si,ax ; skip field
jmp Vendloop
InterpBootp endp
;************************************************************************
;* XtractIpNums
;************************************************************************
XtractIpNums proc near
sub cx,ax ; wanted - already got
shl ax,1
shl ax,1
add di,ax ; append to what we got
shl cx,1
shl cx,1
jmp short XtractNBytes
Xtract4Bytes:
mov cl,4
XtractNBytes:
lodsb
cmp cl,al ; as many as we want?
jbe XtractOkLen
mov cl,al ; - no, take what there is
XtractOkLen:
xor ch,ch
xor ah,ah
push cx
push ax
push si
rep movsb ; copy field
pop si
pop ax
add si,ax ; advance field ptr
pop cx
shr cx,1
shr cx,1 ; cx = IP #'s read
ret
XtractIpNums endp
;========================================================================
; endinclude